// ignore_for_file: unused_element

part of "kit.dart";

/// 一个Table必须：
/// 1. 有id作为int自增主键
/// 2. 有user_id作为int外键，并且需要建立索引
abstract class TableForUser<T> extends TableGeneral<T> {
  /// 寻找某个用户的所有对象
  Future<List<T>> findFor(int userId) async {
    final results = await argConn.value.execute(Sql.named("""
      SELECT *
      FROM $tableName
      WHERE user_id = @userId;
    """), parameters: {
      'userId': userId,
    });

    return results.map((row) => unzip(row.toColumnMap())).toList();
  }
}

/// 由于有些操作仅仅需要id就可以，实际上什么表格都是一样的
abstract class TableGeneral<T> extends Table<T> {
  @override
  Future<void> deleteTable() async =>
      await conn.execute(Sql.named("DROP TABLE IF EXISTS $tableName;"));

  @override
  Future<List<T>> findAll() async {
    final results = await conn.execute(Sql.named("""
    SELECT *
    FROM $tableName;
  """));

    return results.map((row) => unzip(row.toColumnMap())).toList();
  }

  @override
  Future<void> delete(int id) async {
    final T? found = await find(id);
    if (found == null) throw BugDev("表格[$tableName]id[$id]不存在，无法删除");

    await conn.execute(Sql.named("""
      DELETE FROM $tableName
      WHERE id = @id;
    """), parameters: {'id': id});
  }

  @override
  Future<T?> find(int id) async {
    final results = await conn.execute(Sql.named("""
      SELECT *
      FROM $tableName
      WHERE id = @id;
    """), parameters: {'id': id});

    if (results.isNotEmpty) {
      return unzip(results.first.toColumnMap());
    } else {
      return null;
    }
  }
}

/// 由于用户表格不可能有外键，因此无需findFor函数，但其他都是共用的
abstract class Table<T> {
  /// 表格的唯一名字
  String get tableName;

  /// 表格的Postgresql连接，以和全局的connection解耦
  Connection get conn;

  /// 将对象反序列化的函数
  T unzip(Json raw);

  /// 自定义创建、删除表格的SQL语句，不对外公开，而是由其他函数统一管理
  Future<void> createTable();
  Future<void> deleteTable();

  /// 寻找某个特定id的对象，可能找不到
  Future<T?> find(int id);

  /// 寻找整个表格中的所有内容
  Future<List<T>> findAll();

  /// 创建并返回对象，输入任意多的参数
  Future<T> create(Json args);

  /// 更新某个对象，需要子类自行指定sql语句
  /// 因为要更新哪些属性还是未知的
  Future<void> update(T item);

  /// 根据id删除某个对象
  Future<void> delete(int id);
}
